package com.tanlu.tcc.manager;

import com.tanlu.tcc.annotation.TransactionStatus;
import com.tanlu.tcc.domain.Command;
import com.tanlu.tcc.domain.Transaction;
import com.tanlu.tcc.mq.Sender;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Deque;
import java.util.LinkedList;

@Component
public class TransactionManager {

    @Autowired
    private Sender sender;

    private static final ThreadLocal<Deque<Transaction>> CURRENT = new ThreadLocal<Deque<Transaction>>();


    public void registerTransaction(Transaction transaction) {
        if (CURRENT.get() == null) {
            CURRENT.set(new LinkedList<Transaction>());
        }
        CURRENT.get().push(transaction);
    }

    public Transaction beginTransaction(Transaction transaction) {
        registerTransaction(transaction);
        return transaction;
    }



    public Transaction getCurrentTransaction() {
        if (isTransactionActive()) {
            return CURRENT.get().peek();
        }
        return null;
    }


    public boolean isTransactionActive() {
        Deque<Transaction> transactions = CURRENT.get();
        return transactions != null && !transactions.isEmpty();
    }

    public void commit() {
        final Transaction transaction = getCurrentTransaction();
        if(transaction != null && isTransactionActive()) {
            if (!isOuttime(transaction)) {
                transaction.setStatus(TransactionStatus.Confirm);
                Command command = new Command();
                command.setTransactionStatus(TransactionStatus.Confirm);
                command.setObject(transaction);
                sender.send(command);
            } else {
                System.out.println("timer out");
                rollback();
            }
        }
    }

    public void rollback() {
        final Transaction transaction = getCurrentTransaction();
        if(transaction != null && isTransactionActive()) {
            transaction.setStatus(TransactionStatus.Cancel);
            Command command = new Command();
            command.setTransactionStatus(TransactionStatus.Cancel);
            command.setObject(transaction);
            sender.send(command);
        }
        endTranscation(transaction);
    }

    public boolean isOuttime(Transaction transaction) {
        long lastUpdateTime = transaction.getLastUpdateTime().getTime();
        long currentTime = System.currentTimeMillis();
        long outtime =transaction.getOutTime();
        System.out.println("is out time:" + outtime);
        return (currentTime - lastUpdateTime) > outtime ? true : false;
    }

    public void endTranscation(Transaction transaction) {
        if (isTransactionActive() && transaction != null) {
            Transaction currentTransaction = getCurrentTransaction();
            if (currentTransaction.getTransactionId().equals(transaction.getTransactionId())) {
                System.out.println("end");
                CURRENT.get().pop();
                if (CURRENT.get().size() == 0) {
                    CURRENT.remove();
                }
            } else {
                throw new RuntimeException("Illegal transaction when clean after completion");
            }
        }
    }



}


